package com.szholly.plug.form.validation;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.springframework.stereotype.Component;

import com.szholly.utils.spring.SpringBeanFactory;
import com.szholly.data.general.Field;
import com.szholly.data.general.GlobalParameter;
import com.szholly.data.general.ITable;
import com.szholly.data.general.ITableFactory;
import com.szholly.data.general.IWorkspace;
import com.szholly.data.general.IWorkspaceFactory;
import com.szholly.data.general.RowBase;
import com.szholly.data.general.interceptor.DbEditInterceptorClass;
import com.szholly.data.general.interceptor.DbEditType;
import com.szholly.data.general.interceptor.InterceptorRegister;
import com.szholly.data.general.interceptor.defulat.UniqueCheckException;
import com.szholly.plug.form.excel.utils.StringUtil;

/**
 * 定义数据验证拦截器
 */
@Component
public class ValidationEditInterceptor extends DbEditInterceptorClass {
	
	/**
	 * 注册拦截接口
	 */
	static {
		ValidationEditInterceptor interceptor = new ValidationEditInterceptor();
		InterceptorRegister.RegDbInterceptor(interceptor);
	}
	
	/**
	 * 验证entity 是否合法，不合法会抛出相应的异常
	 * @param table，通过table可以获取fields信息，进而获得没有field是的验证规则
	 * @param editEntitys 需要验证的实体，可以转换为Map的对象，如：RowBase,HashMap
	 * @param isUpdate 是否为更新记录
	 */
	public static void validate(ITable table, Object editEntitys,boolean isUpdate){
		@SuppressWarnings("rawtypes")
		Map row = (Map)editEntitys;
		Field[] fields = table.getFields();
		innerValidate(row,fields,isUpdate,table);
	}
	
	/**
	 * 验证entity 是否合法，不合法会抛出相应的异常
	 * @param table，通过table可以获取fields信息，进而获得没有field是的验证规则
	 * @param editEntitys 需要验证的实体，可以转换为Map的对象，如：RowBase,HashMap
	 * @param isUpdate 是否为更新记录
	 */
	public static void validate(String tableName, Object editEntitys,boolean isUpdate){
		ITableFactory tableFactory = (ITableFactory) SpringBeanFactory.getBean("TableFactory");
		ITable pTable = tableFactory.openTable(tableName);
		validate(pTable,editEntitys,isUpdate);
	}

	@Override
	public void BeforeDbEditOption(ITable table, Object editEntitys,
			DbEditType editType) {
		// 如果是新增，并且状态值为空，处理默认值
		if((editType == DbEditType.Insert || editType == DbEditType.Update)
				&& editEntitys instanceof RowBase){
			RowBase row = (RowBase)editEntitys;
			Field[] fields = table.getFields();
			innerValidate(row,fields,editType == DbEditType.Update,table);
		}
	}
	
	private static void innerValidate(@SuppressWarnings("rawtypes") Map row, Field[] fields, boolean isUpdate,ITable table){
		String regEx = null;
		for(Field field:fields){
			
			//如果是更新，只检查更新的字段
			if(isUpdate && !row.containsKey(field.getFieldName())){
				continue;
			}
			
			//验证空值
			String value = row.get(field.getFieldName())==null?"":row.get(field.getFieldName()).toString();
			if(field.getAllowNull()==false){
				if(!"GUID".equals(field.getFieldName()) && StringUtil.IsNullOrEmpty(value)){
					throw new FieldIsNullException(field.getFieldAliasName()+"("+field.getFieldName()+") 不能为空！");
				}
			}
			
			//跳过传真、联系电话、联系人、站点名称的验证
			if("FAX".equals(field.getFieldName()) || "MOBILE".equals(field.getFieldName())
					|| "CONTACT".equals(field.getFieldName()) || "ID".equals(field.getFieldName()))
			{
				continue;
			}
			
			regEx = field.getRegEx();
			if(StringUtil.IsNotNullOrEmpty(regEx)){
				//验证正则表达式
				if(StringUtil.IsNotNullOrEmpty(value)){
					if(!value.matches(regEx)){
						throw new RegexNotMatchException("     "+field.getFieldAliasName()+" 格式不正确！");
					}
				}
			}
			
			//验证字段长度
			int len = field.getMaxLen();//nvarchar2 
			if ("null".equals(value)) {
				len=0;
			}
			if(len>0 && value.length()>0){
				String str = value.replaceAll("[^\\x00-\\xff]", "**");//非ascii字符占2个字节
				if(str.length()>len){
					throw new StringLengthException(field.getFieldAliasName()+" 长度过长！");
				}
			}
			if(!StringUtil.IsNullOrEmpty(field.getUniqueGroup())){
				checkUnique(row, isUpdate, table, field, value);
			}
		}
	}

	/**
	 * 验证字段的唯一性，其中唯一字段可能是一组
	 * 比如站点污染物的阈值表，一个污染物对应多个阈值，同一个污染物下的阈值名称应该是唯一的
	 * 那么这里的污染物id和阈值名称共同组成这个唯一字段组，所以在检查的时候需要考虑这一点
	 * @param model
	 * @param isUpdate
	 * @param table
	 * @param field
	 * @param value
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private static void checkUnique(Map model, boolean isUpdate, ITable table,
			Field field, String value) {
		
		IWorkspaceFactory workspaceFactory = (IWorkspaceFactory) SpringBeanFactory.getBean("WorkspaceFactory");
		IWorkspace pWorkspace = workspaceFactory.openWorkspace();
		Field[] keyFields = table.getKeyFields();
		HashMap<String, List<Field>> uniqueFilesMap = table.getUniqueFieldMap();
		
		if(keyFields.length < 1){
			throw new RuntimeException(table.getTableName() + "表元数据没有设置主键！");
		}
		
		Object keyValue = model.get(keyFields[0].getFieldName());
		
		if(StringUtil.IsNullOrEmpty(keyValue) && !isUpdate){
			if(!isUpdate){
				model.put(keyFields[0].getFieldName(),UUID.randomUUID().toString());
			}
			else{
				throw new RuntimeException(table.getTableName() + "主键不能为空！");
			}
		}
		
		List<GlobalParameter> pc = new ArrayList<>();
		Object checkRresult =null;
		String checkUniqueSql = "";
		List<Field> uniqupFields = uniqueFilesMap.get(field.getUniqueGroup().toUpperCase());
		String uniqueWhere = "";
		for(Field uniqueFieldItem : uniqupFields){
			String  uniqueFieldItemName = uniqueFieldItem.getFieldName();
			uniqueWhere += " and " + uniqueFieldItemName + "=@"+uniqueFieldItemName;
			pc.add(new GlobalParameter(uniqueFieldItemName, model.get(uniqueFieldItemName)));
		}
		
		if(!isUpdate){
			checkUniqueSql = " SELECT COUNT(*) FROM "+table.getTableName() + " where 1=1 " + uniqueWhere;
		}
		else{
			checkUniqueSql = " SELECT COUNT(*) FROM "+table.getTableName() + " where "+keyFields[0].getFieldName()+"!=@keyValue " + uniqueWhere;
			pc.add(new GlobalParameter("keyValue",keyValue));
		}
		
		pc.add(new GlobalParameter("value",value));
		
		checkRresult =  pWorkspace.getExecuteScalar(checkUniqueSql, pc.toArray(new GlobalParameter[pc.size()]));
			 
		if(checkRresult != null && !"0".equals(checkRresult.toString())){
			throw new UniqueCheckException(field.getFieldAliasName()+" 不能重复");
		}
	}

	@Override
	public void DbEditOptionException(ITable table, Object editEntitys,
			DbEditType editType, Exception ex) {
	}

	@Override
	public void AfterDbEditOption(ITable table, Object editEntitys,
			DbEditType editType) {
	}

	@Override
	public String getInterceptorName() {
		return "后台验证拦截器";
	}
	
}
